home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / OpenDoc 1.2b2c1 / Implementation / Utilities / DlogUtil.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-13  |  40.6 KB  |  1,544 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        DlogUtil.cpp
  3.  
  4.     Contains:    implementation of dialog utility functions
  5.  
  6.     Owned by:    Tantek Çelik
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.         <13>    02.10.1996    NP        1386083: Make sure that these routines can
  13.                                     work without OpenDoc.
  14.         <12>     9/13/96    EL        1306385: Add SetUpPopControlValue.
  15.         <11>      9/4/96    EL        1383592: Need to save and restore port when
  16.                                     calling dispatch.
  17.         <10>     7/10/96    RA        1363236: Cosemtic Document/PartInfo dlg
  18.                                     fixes
  19.          <9>     6/27/96    jpa        1361886: Added LookupString
  20.          <8>     6/22/96    EL        1344140: make sure OK button can be
  21.                                     disabled. 1210509 make sure ShowAlert can
  22.                                     be called from Pref.
  23.          <7>      6/6/96    EL        1293250: SetDialogTextStyle should
  24.                                     recalculate line height and font height.
  25.                                     Code from Jon.
  26.          <6>      5/1/96    JA        1213332: Force 68k alignment of FontSpec
  27.                                     resource type.
  28.          <5>    .04.1996    NP        Comment about not checking for being in the
  29.                                     background before posing alert.
  30.          <4>      1/5/96    eeh        1298401: don't disable keyboard changes
  31.          <3>      1/4/96    eeh        fix header
  32.          <2>      1/4/96    eeh        1226961: make ActivateAllControls
  33.                                     non-static
  34.  
  35.     To Do:
  36.     In Progress:
  37.         
  38. */
  39.  
  40. #ifndef _EXCEPT_
  41. #include <Except.h>
  42. #endif
  43.  
  44. #ifndef SOM_Module_OpenDoc_Errors_defined
  45. #include <ErrorDef.xh>
  46. #endif
  47.  
  48. #ifndef _DLOGUTIL_
  49. #include <DlogUtil.h>
  50. #endif
  51.  
  52. #ifndef _PLFMDEF_
  53. #include <PlfmDef.h>
  54. #endif
  55.  
  56. #ifndef _ODUTILS_
  57. #include <ODUtils.h>
  58. #endif
  59.  
  60. #ifndef SOM_ODMenuBar_xh
  61. #include <MenuBar.xh>
  62. #endif
  63.  
  64. #ifndef SOM_ODDispatcher_xh
  65. #include <Disptch.xh>
  66. #endif
  67.  
  68. #ifndef SOM_ODSession_xh
  69. #include <ODSessn.xh>
  70. #endif
  71.  
  72. #ifndef SOM_ODWindowState_xh
  73. #include <WinStat.xh>
  74. #endif
  75.  
  76. #ifndef SOM_ODClipboard_xh
  77. #include <Clipbd.xh>
  78. #endif
  79.  
  80. #ifndef _ODMEMORY_
  81. #include <ODMemory.h>
  82. #endif
  83.  
  84. #ifndef __GESTALTEQU__
  85. #include <GestaltEqu.h>
  86. #endif
  87.  
  88. #ifndef __TOOLUTILS__
  89. #include <ToolUtils.h>
  90. #endif
  91.  
  92. #ifndef _PASCLSTR_
  93. #include <PasclStr.h>
  94. #endif
  95.  
  96. #ifndef __DIALOGS__
  97. #include <Dialogs.h>
  98. #endif
  99.  
  100. #ifndef __TEXTEDIT__
  101. #include <TextEdit.h>
  102. #endif
  103.  
  104. #ifndef __PALETTES__
  105. #include <Palettes.h>
  106. #endif
  107.  
  108. #ifndef _MEMMGR_
  109. #include <MemMgr.h>
  110. #endif
  111.  
  112. #ifndef _ODDEBUG_
  113. #include <ODDebug.h>
  114. #endif
  115.  
  116. #ifndef _USERSRCM_
  117. #include <UseRsrcM.h>
  118. #endif
  119.  
  120. #ifndef SOM_ODNameSpaceManager_xh
  121. #include <NmSpcMg.xh>
  122. #endif
  123.  
  124. #ifndef SOM_Module_OpenDoc_Commands_defined
  125. #include <CmdDefs.xh>
  126. #endif
  127.  
  128. #ifndef SOM_ODStorageSystem_xh
  129. #include <ODStor.xh>
  130. #endif
  131.  
  132. #ifndef SOM_ODPlatformTypeList_xh
  133. #include <PfTypLs.xh>
  134. #endif
  135.  
  136. #ifndef _TEMPOBJ_
  137. #include "TempObj.h"
  138. #endif
  139.  
  140. // Types
  141. struct _MenuItemInfo
  142. {
  143.     MenuHandle    menu;
  144.     short        item;
  145.     Str255        text;
  146.     short        cmdChar;
  147.     short        iconID;
  148.     short        markChar;
  149.     Style        textStyle;
  150. };
  151. typedef struct _MenuItemInfo MenuItemInfo;
  152.  
  153. struct _DialogBoxInfo
  154. {
  155.     MenuItemInfo    redo;
  156.     // Can put other things in here later on
  157.     // like supporting movable modals, etc.
  158. };
  159. typedef struct _DialogBoxInfo DialogBoxInfo;
  160.  
  161. // Key codes
  162. // const char kEscapeKey        = 0x1B;
  163. // const char kUpArrowKey        = 0x1E;
  164. // const char kDownArrowKey    = 0x1F;
  165. const char kPageUpKey        = 0x0B;
  166. const char kPageDownKey        = 0x0C;
  167. const char kHomeKey            = 0x01;
  168. const char kEndKey            = 0x04;
  169.  
  170. // Control settings
  171. const short kControlInactive = 255;
  172. const short kControlActive = 0;
  173.  
  174. // Dialog item assumptions
  175. const short kOKButton = 1;
  176. const short kCancelButton = 2;
  177.  
  178. // Memory requirements
  179. const size_t kODMinFreeSpaceToShowDialog = 4 * 1024;
  180.     
  181. static Environment        *sEv;
  182. static ODSession        *sSession;
  183. static ModalFilterUPP    sFilter = kODNULL;
  184. static ModalFilterUPP    sButtonKeyFilter = kODNULL;
  185. static ModalFilterUPP    sArrowKeyFilter = kODNULL;
  186. static UserItemUPP        sOutlineDrawProc = kODNULL;
  187. static short            sCmdKeyStrResID = 0;    
  188. static DialogScriptData*
  189.                         sDlogScriptData = kODNULL;    
  190.     // Res ID of STR# that contains cmd-keys for buttons
  191.  
  192. static DialogBoxInfo* sDialogInfo = kODNULL;
  193.  
  194. // Private functions
  195. static void SaveAndDeleteMenuItem( MenuHandle menu, short item, MenuItemInfo *savedItem );
  196. static void RestoreMenuItem( MenuItemInfo *savedItem );
  197.  
  198.  
  199. //==============================================================================
  200. // Preflighting Dialogs and Alerts
  201. //==============================================================================
  202.  
  203. //------------------------------------------------------------------------------
  204. // Centering
  205. //
  206. //    This function is used by the shell when there may not be any OpenDoc
  207. //    services, not even a session. So check for those services.
  208. //------------------------------------------------------------------------------
  209.  
  210. static ODBoolean
  211. GetFrontWindowBounds( Rect &bounds )
  212. {
  213.     WindowPtr wp;
  214.     {
  215.         ODWindowState* winState = sSession->GetWindowState(sEv);
  216.         if (winState)
  217.         {
  218.             TempODWindow win
  219.                     = sSession->GetWindowState(sEv)->AcquireActiveWindow(sEv);
  220.             wp = win ? win->GetPlatformWindow(sEv) : FrontWindow();
  221.         }
  222.         else
  223.             wp = NULL;
  224.     }
  225.     
  226.     if( wp ) {
  227.         bounds = wp->portRect;
  228.         Rect *mapBounds;
  229.         if( wp->portBits.rowBytes & 0xC000 )            // Color port
  230.             mapBounds= &(**((CGrafPtr)wp)->portPixMap).bounds;
  231.         else
  232.             mapBounds= &wp->portBits.bounds;
  233.         OffsetRect(&bounds,-mapBounds->left,-mapBounds->top);
  234.         return kODTrue;
  235.     } else {
  236.         bounds = ODQDGlobals.screenBits.bounds;        // No win, use main screen
  237.         bounds.top += GetMBarHeight();
  238.         return kODFalse;
  239.     }
  240. }
  241.  
  242.  
  243. static void
  244. GetWindowsMainScreen( const Rect &windowBounds, Rect &screenBounds )
  245. {
  246.     long area=0;
  247.     
  248.     GDHandle gdh;
  249.     Rect devBounds,sectBounds;
  250.     long maxArea=0;
  251.     
  252.     for( gdh = GetDeviceList(); gdh; gdh = GetNextDevice(gdh) ) {
  253.         devBounds = (**gdh).gdRect;
  254.         if( gdh == GetMainDevice() )
  255.             devBounds.top += GetMBarHeight();
  256.         if( SectRect(&devBounds,&windowBounds,§Bounds) ) {
  257.             area = (sectBounds.right-sectBounds.left) * (long)(sectBounds.bottom-sectBounds.top);
  258.             if( area > maxArea ) {
  259.                 maxArea = area;                    // Best screen so far
  260.                 screenBounds = devBounds;
  261.                 if( gdh==GetMainDevice() )
  262.                     screenBounds.right -= 30;    // Leave room for Finder disk icons
  263.             }
  264.         }
  265.     }
  266.     if( area==0 ) {
  267.         screenBounds = ODQDGlobals.screenBits.bounds;        // Default: use main screen
  268.         screenBounds.top += GetMBarHeight();
  269.     }
  270. }
  271.  
  272.  
  273. static void
  274. CenterDialog( short ¢erFlag, Rect &bounds )
  275. {
  276.     /* Do centering manually. Why? Even though the Dialog Manager handles
  277.        automatic centering, it calls FrontWindow to find the parent window.
  278.        This will return an incorrect window (a floater) if there are floating
  279.        windows. We have to reproduce the centering effect but using the
  280.        actual frontmost non-floating window. */
  281.     const short noAutoCenter                    = 0x0000;
  282.     const short centerParentWindowScreen        = 0x680A;        // From Types.r
  283.     const short alertPositionParentWindowScreen = 0x700A;
  284.     const short centerParentWindow                = 0xA80A;
  285.     const short alertPositionParentWindow        = 0xB00A;
  286.     // We don't do anything for other flags.
  287.     
  288.     if( (centerFlag != centerParentWindowScreen) &&  (centerFlag != alertPositionParentWindowScreen)
  289.         && (centerFlag != centerParentWindow) &&  (centerFlag != alertPositionParentWindow) )
  290.         return;
  291.     
  292.     Rect centerBounds;
  293.     if( GetFrontWindowBounds(centerBounds)
  294.             && (centerFlag==centerParentWindowScreen ||
  295.                 centerFlag==alertPositionParentWindowScreen) ) {
  296.         Rect screenBounds;
  297.         GetWindowsMainScreen(centerBounds,screenBounds);
  298.         centerBounds = screenBounds;
  299.     }
  300.     
  301.     Point pos;
  302.     pos.h = ((centerBounds.right-centerBounds.left)-(bounds.right-bounds.left)) >>1;
  303.     pos.v = ((centerBounds.bottom-centerBounds.top)-(bounds.bottom-bounds.top));
  304.     if( centerFlag==centerParentWindowScreen || centerFlag==centerParentWindow )
  305.         pos.v /= 2;
  306.     else if( centerFlag==alertPositionParentWindowScreen || centerFlag==alertPositionParentWindow )
  307.         pos.v /= 3;
  308.         
  309.     pos.h += centerBounds.left;
  310.     pos.v += centerBounds.top;
  311.     OffsetRect(&bounds, pos.h-bounds.left, pos.v-bounds.top);
  312.     centerFlag = noAutoCenter;            // It's already centered now
  313. }
  314.  
  315.  
  316. //------------------------------------------------------------------------------
  317. // PreflightDialog
  318. //------------------------------------------------------------------------------
  319.  
  320. static Handle
  321. PreflightDialog( ODBoolean isDLOG, short id )
  322. {
  323.     Handle rsrc;
  324.     ODBoolean ok;
  325.     
  326.     if( isDLOG ) {
  327.         // Load DLOG and DITL:
  328.         rsrc = Get1Resource('DLOG', id);
  329.         DialogTemplate** dlogTemplate = (DialogTemplate**)rsrc;
  330.         ok = dlogTemplate && Get1Resource('DITL', (*dlogTemplate)->itemsID);
  331.         if( ok ) {
  332.             // Get the centering flag & adjust dialog centering:
  333.             HLock(rsrc);
  334.             size_t centerFlag = (size_t) &(**dlogTemplate).title;
  335.             centerFlag += *(unsigned char*)centerFlag +1;    // skip title
  336.             centerFlag += (centerFlag & 1);                    // word align
  337.             CenterDialog(*(short*)centerFlag, (**dlogTemplate).boundsRect);
  338.             HUnlock(rsrc);
  339.         }
  340.     } else {
  341.         // Load ALRT and DITL:
  342.         rsrc = Get1Resource('ALRT', id);
  343.         AlertTemplate** alrtTemplate = (AlertTemplate**)rsrc;
  344.         ok = alrtTemplate && Get1Resource('DITL', (*alrtTemplate)->itemsID);
  345.         if( ok ) {
  346.             // Get the centering flag & adjust alert centering:
  347.             HLock(rsrc);
  348.             short *centerFlag = (short*)( (size_t)*alrtTemplate + sizeof(AlertTemplate) );
  349.             CenterDialog(*centerFlag,(**alrtTemplate).boundsRect);
  350.             HUnlock(rsrc);
  351.         }
  352.     }
  353.     
  354.     if( !ok ) {
  355. #if ODDebug
  356.         OSErr err = ResError();
  357.         WARN("Could not load dialog/alert %hd: error %hd",id,err);
  358. #endif
  359.         SysBeep(2);                            // At least give some indication
  360.         rsrc = kODNULL;
  361.     } else {
  362.         // Bail if space is really, really low. Don't even beep, this might cause
  363.         // a large 'snd' to be loaded.
  364.         if( !ODHaveFreeSpace(kODMinFreeSpaceToShowDialog,kODMinFreeSpaceToShowDialog,
  365.                              kODTrue) ) {
  366.             WARN("Whoa, not enough memory to show a dialog/alert!");
  367.             ReleaseResource(rsrc);
  368.             rsrc = kODNULL;
  369.         }
  370.     }
  371.     
  372.     return rsrc;
  373. }
  374.  
  375.  
  376. //==============================================================================
  377. // Displaying Dialogs and Alerts
  378. //==============================================================================
  379.  
  380. DialogPtr
  381. ODGetNewDialog( Environment *ev, short resID, ODSession *session, ODBoolean defaultButtons )
  382. {
  383.     ASSERT(session!=kODNULL, kODErrIllegalNullInput);
  384.  
  385.     sEv = ev ?ev :somGetGlobalEnvironment();
  386.     sSession = session;
  387.  
  388.     Handle dlogRsrc = PreflightDialog(kODTrue,resID);
  389.     if( ! dlogRsrc )
  390.         return kODNULL;
  391.  
  392.     DialogPtr dlog = ::GetNewDialog(resID,kODNULL,(WindowPtr)-1L);
  393.     if( dlog ) {
  394.         if( defaultButtons ) {
  395.             ::SetDialogDefaultItem(dlog,kStdOkItemIndex);
  396.             ::SetDialogCancelItem(dlog,kStdCancelItemIndex);
  397.         }
  398.         ::SetDialogTracksCursor(dlog,kODTrue);
  399.         
  400.         sCmdKeyStrResID = 0;    // Don't use command-key lookup unless told to
  401.         
  402.         InitCursor();            // Show arrow
  403.     }
  404.     
  405.     ReleaseResource(dlogRsrc);
  406.     
  407.     return dlog;
  408. }
  409.  
  410. ODSShort
  411. ShowAlert(Environment *ev, ODSShort alertID, ModalFilterUPP modalFilter, ODSession *session)
  412. {
  413.     ASSERT(session != kODNULL, kODErrIllegalNullInput);
  414.  
  415.     CUsingLibraryResources r;
  416.  
  417.     SetCursor(&(ODQDGlobals.arrow));
  418.  
  419.     sEv = ev ?ev :somGetGlobalEnvironment();
  420.     sSession = session;
  421.  
  422.     Handle alrtRsrc = PreflightDialog(kODFalse,alertID);
  423.     if( ! alrtRsrc )
  424.         return cancel;
  425.     
  426.     // Success at last!
  427.  
  428.     // THIS ALERT SHOULD PROBABLY BE PROTECTED WITH A CHECK FOR THE APP
  429.     //    BEING IN THE BACKGROUND
  430.     short alertReturn = Alert(alertID, modalFilter);
  431.     
  432.     ReleaseResource(alrtRsrc);
  433.  
  434.     return alertReturn;
  435. }
  436.  
  437. pascal Boolean
  438. ODDialogFilterProc( DialogPtr dp, EventRecord *event, short *item )
  439. {
  440.     ODBoolean dispatch = kODFalse;
  441.     
  442.     if( event->what==updateEvt || event->what==activateEvt ) {
  443.         if( (WindowPtr)event->message != dp )    // Dispatch updates/activates of other windows
  444.             dispatch = kODTrue;
  445.             
  446.     } else if( event->what==nullEvent || event->what==osEvt )    // Ditto null/suspend/resume
  447.         dispatch = kODTrue;
  448.     
  449.     else if( event->what==mouseDown ) {
  450.         WindowPtr wp;
  451.         if( ::FindWindow(event->where,&wp)==inDrag && wp==dp ) {    // Dragging me!
  452.             Rect bounds = ODQDGlobals.screenBits.bounds;
  453.             DragWindow(dp,event->where,&bounds);
  454.             event->what = nullEvent;
  455.         }
  456.         
  457.     } else if( event->what==keyDown ) {
  458.         // Cmd-A means select all if there is editable text:
  459.         short curTextItem = ((DialogPeek)dp)->editField + 1;
  460.         char key = event->message & charCodeMask;
  461.         if( curTextItem>0 && (key=='a' || key=='A') && (event->modifiers & cmdKey) )
  462.             SelectDialogItemText(dp, curTextItem, 0, 32767);
  463. #ifdef TO_BE_DELETED
  464.         else
  465.         {
  466.             long scriptNum = GetScriptManagerVariable( smKeyScript );
  467.             long curScript = FontToScript(dp->txFont);
  468.             if ( curScript != scriptNum )
  469.             {
  470. //                DebugStr( "\pChanging system font;g" );
  471.                 short myFont = GetScriptVariable( scriptNum, smScriptAppFond );
  472.                 WindowPtr savePort;
  473.                 GetPort(&savePort);
  474.                 SetPort(dp);
  475.                 TextFont( myFont );
  476.                 SetPort(savePort);
  477.             }
  478.         }
  479. #endif /* TO_BE_DELETED */
  480.     }
  481.     
  482.     if( dispatch ) {
  483.         WindowPtr savePort; ODVolatile(savePort);
  484.         GetPort(&savePort);
  485.         TRY{
  486.             ODDispatcher* dispatcher = sSession->GetDispatcher(sEv);
  487.             if (dispatcher)
  488.                 dispatcher->Dispatch(sEv, (ODEventData*)event);
  489.         }CATCH_ALL{
  490.         }ENDTRY
  491.         SetPort(savePort);
  492.     }
  493.     
  494.     // Forward other events to the standard filter-proc:    
  495.     ModalFilterUPP proc;
  496.     OSErr err= GetStdFilterProc(&proc);
  497.     if( err==noErr )
  498.         return CallModalFilterProc(proc, dp,event,item);    // Call through to std filter-proc
  499.     else {
  500.         WARN("Couldn't get std filter proc!");
  501.         return false;
  502.     }
  503. }
  504.  
  505.  
  506. ModalFilterUPP
  507. GetODDialogFilter( )
  508. {
  509.     if( !sFilter )
  510.         sFilter = NewModalFilterProc(&ODDialogFilterProc);
  511.     return sFilter;
  512. }
  513.  
  514.  
  515. //==============================================================================
  516. // Filter Procs & Such
  517. //==============================================================================
  518.  
  519. static void
  520. ActivateControl(DialogPtr dialog, short item, Boolean isActivate)
  521. {
  522.     short            itemType;
  523.     Rect            itemRect;
  524.     ControlHandle    cntrlHandle;
  525.  
  526.     GetDialogItem(dialog, item, &itemType, (Handle*) &cntrlHandle, &itemRect);
  527.     ASSERT_CONTROL_ITEM(itemType);
  528.     
  529.     CUsingLibraryResources r;
  530.  
  531.     if ( isActivate )
  532.     {
  533.         HiliteControl(cntrlHandle, GetControlReference(cntrlHandle));
  534.     }
  535.     else
  536.     {
  537.         SetControlReference(cntrlHandle, (**cntrlHandle).contrlHilite);
  538.         HiliteControl(cntrlHandle, kControlInactive);
  539.     }
  540. }
  541.  
  542. void
  543. ActivateAllControls(DialogPtr dialog, Boolean isActivate)
  544. {
  545.     short            itemType;
  546.     Rect            itemRect;
  547.     ControlHandle    cntrlHandle;
  548.     short            item;
  549.  
  550.     for (item = 1; item <= CountDITL(dialog); ++item)
  551.     {
  552.         GetDialogItem(dialog, item, &itemType, (Handle*) &cntrlHandle, &itemRect);
  553.         itemType &= ~kItemDisableBit;
  554.         if ( itemType>=ctrlItem && itemType<=ctrlItem+resCtrl )
  555.             ActivateControl(dialog, item, isActivate);
  556.     }
  557. }
  558.  
  559.  
  560. pascal Boolean ODArrowKeyFilterProc( DialogPtr dlg, ODEventData* event,
  561.         short* itemHit )
  562. {
  563.     Boolean result;
  564.     if ( event->what == keyDown || event->what == autoKey )
  565.     {
  566.         result = kODTrue;
  567.         char key = event->message & charCodeMask;
  568.         ODBoolean cmdKeyDown = (event->modifiers & cmdKey) != 0;
  569.         ODBoolean optionKeyDown = (event->modifiers & optionKey) != 0;
  570.         switch ( key )
  571.         {
  572.             case kUpArrowKey:
  573.                 *itemHit = cmdKeyDown ? optionKeyDown ? kODHomeArrowItem :
  574.                         kODPageUpArrowItem : kODUpArrowItem;
  575.                 break;
  576.             case kDownArrowKey:
  577.                 *itemHit = cmdKeyDown ? optionKeyDown ? kODEndArrowItem :
  578.                         kODPageDownArrowItem : kODDownArrowItem;
  579.                 break;
  580.  
  581.             case kPageUpKey:
  582.                 *itemHit = kODPageUpArrowItem;
  583.                 break;
  584.             case kPageDownKey:
  585.                 *itemHit = kODPageDownArrowItem;
  586.                 break;
  587.             case kHomeKey:
  588.                 *itemHit = kODHomeArrowItem;
  589.                 break;
  590.             case kEndKey:
  591.                 *itemHit = kODEndArrowItem;
  592.                 break;
  593.  
  594.             default:
  595.                 result = kODFalse;
  596.         }
  597.     }
  598.     else
  599.         result = kODFalse;
  600.     return result || ODButtonKeyFilterProc( dlg, event, itemHit );
  601. }
  602.  
  603.  
  604. ModalFilterUPP
  605. GetODArrowKeyFilterProc( )
  606. {
  607.     if( !sArrowKeyFilter )
  608.         sArrowKeyFilter = NewModalFilterProc(&ODArrowKeyFilterProc);
  609.     return sArrowKeyFilter;
  610. }
  611.  
  612. // DMc: this debugging code disables use of enter to mean 'OK' when this var is set:
  613. // #if ODDebug
  614. // int gODButtonKeyNoEnterOkay = 0; // set to non-zero to disable enter for okay
  615. // #endif
  616.  
  617. pascal Boolean
  618. ODButtonKeyFilterProc(DialogPtr dialog, EventRecord *event, short *itemHit)
  619. {    
  620.     Rect            itemRect;
  621.     short            itemType;
  622.     Handle            itemHandle;
  623.     short            myItemHit = 0;
  624.  
  625.     const short        kEscKeyCode = 0x35;    // Virtual key code for the escape key
  626.  
  627.     if ( event->what == keyDown )
  628.     {
  629.         char key = event->message & charCodeMask;
  630.         switch ( key )
  631.         {
  632.             case kReturnKey:
  633.             case kEnterKey:
  634.                 GetDialogItem(dialog, kOKButton, &itemType, &itemHandle, &itemRect);
  635.                 ASSERT_CONTROL_ITEM(itemType);
  636.  
  637. // DMc: this debugging code disables use of enter to mean 'OK' when a var is set:
  638. // #if ODDebug
  639. //                 if ( !gODButtonKeyNoEnterOkay || key != kEnterKey )
  640. //                 {
  641. //                     if ( (**(ControlHandle)itemHandle).contrlHilite == kControlActive )
  642. //                         myItemHit = kOKButton;
  643. //                 }
  644. // #else
  645.                 if ( (**(ControlHandle)itemHandle).contrlHilite == kControlActive )
  646.                     myItemHit = kOKButton;
  647. // #endif /*ODDebug*/
  648.                     
  649.                 break;
  650.             
  651.             case kEscapeKey:
  652.                 // Ensure that the escape key, not the clear key, was pressed
  653.                 if ( (event->message & keyCodeMask) == (kEscKeyCode << 8) )
  654.                 {
  655.                     GetDialogItem(dialog, kCancelButton, &itemType, &itemHandle, &itemRect);
  656.                     if ( (itemType & ~kItemDisableBit) == (ctrlItem+btnCtrl) )
  657.                         myItemHit = kCancelButton;
  658.                 }
  659.                 break;
  660.  
  661.             case '.':        // cmd-period means cancel
  662.                 if ( event->modifiers & cmdKey )
  663.                 {
  664.                     GetDialogItem(dialog, kCancelButton, &itemType, &itemHandle, &itemRect);
  665.                     if ( (itemType & ~kItemDisableBit) == (ctrlItem+btnCtrl) )
  666.                         myItemHit = kCancelButton;
  667.                 }
  668.                 break;
  669.  
  670.             default:
  671.                 if ( (sCmdKeyStrResID != 0)  && (event->modifiers & cmdKey) )
  672.                 {
  673.                     // Attempt to match the key to a key found in the STR# resource
  674.                     Handle stringsHandle = GetResource( 'STR#', sCmdKeyStrResID );
  675.                     if ( stringsHandle )
  676.                     {
  677.                         short     i;
  678.                         short    numStrings = **(short**)stringsHandle;
  679.                         Str255    cmdKeyCode;
  680.                         for ( i = 1; i <= numStrings; ++i )
  681.                         {
  682.                           GetIndString( cmdKeyCode, sCmdKeyStrResID, i );
  683.                           if ( cmdKeyCode[0] && cmdKeyCode[1] == key )
  684.                           {
  685.                             GetDialogItem(dialog, i, &itemType, &itemHandle, &itemRect);
  686.                             ASSERT_CONTROL_ITEM(itemType);
  687.                             if ( (**(ControlHandle)itemHandle).contrlHilite == kControlActive )
  688.                             {
  689.                               myItemHit = i;    // Cool--record the item number that is hit
  690.                               break;
  691.                             }
  692.                           }
  693.                         }
  694.                     } 
  695.                 }
  696.                 break;
  697.         }
  698.  
  699.         if ( myItemHit != 0 )    // need to hilite a button
  700.         {
  701.             FlashButtonItem( dialog, myItemHit );
  702.             *itemHit = myItemHit;
  703.             return kODTrue;
  704.         }
  705.     
  706.     }
  707.     else if ( event->what == activateEvt )
  708.     {
  709.         Boolean isActivate = ((event->modifiers & activeFlag) != 0 );
  710.         ActivateAllControls(dialog, isActivate);
  711.     }
  712.  
  713.     // we only get here if we'd otherwise be returning false; all successes
  714.     // exit at "return kODTrue" above
  715.     return ODDialogFilterProc(dialog,event,itemHit);
  716. }
  717.  
  718.  
  719. ModalFilterUPP
  720. GetODButtonKeyFilterProc( )
  721. {
  722.     if( !sButtonKeyFilter )
  723.         sButtonKeyFilter = NewModalFilterProc(&ODButtonKeyFilterProc);
  724.     return sButtonKeyFilter;
  725. }
  726.  
  727.  
  728. void
  729. ODUseCommandKeyStringsResource( short resID )
  730. {
  731.     sCmdKeyStrResID = resID;
  732. }
  733.  
  734.  
  735. //==============================================================================
  736. // Updating the Menu Bar
  737. //==============================================================================
  738.  
  739. void ODDialogBegin( Environment* ev, ODSession* session, 
  740.             ODMenuBar* currentMenuBar, DialogPtr dialog )
  741. {
  742.     ODUnused(dialog);    // Later on, we can use this to support movable modals
  743.     
  744.     if ( sEv == kODNULL )
  745.         sEv = ev;
  746.  
  747.     if ( sSession == kODNULL )
  748.         sSession = session;
  749.  
  750.     ASSERT(currentMenuBar!=kODNULL,kODErrIllegalNullInput);
  751.     ASSERT(sSession!=kODNULL,kODErrIllegalNullInput);
  752.     
  753.     // Cleanup if needed
  754.     if ( sDialogInfo )
  755.         ODDisposePtr(sDialogInfo);
  756.  
  757.     // Allocate a new menu info record
  758.     sDialogInfo = (DialogBoxInfo*)ODNewPtrClear(sizeof(DialogBoxInfo),kDefaultHeapID);
  759.  
  760.     if ( sDialogInfo )
  761.     {
  762.         ODMenuID        editMenuID = 0;
  763.         ODPlatformMenu    editMenu = kODNULL;
  764.         short            redoItem;
  765.  
  766.         // Delete the Redo menu item so ModalDialog will handle the Edit menu right.
  767.         if ( currentMenuBar->IsCommandRegistered( sEv, kODCommandRedo ) )
  768.         {
  769.             currentMenuBar->GetMenuAndItem(sEv, kODCommandRedo, &editMenuID, &redoItem);
  770.             editMenu = currentMenuBar->GetMenu(sEv, editMenuID );
  771.         }
  772.         if ( editMenu )
  773.             SaveAndDeleteMenuItem(editMenu, redoItem, &sDialogInfo->redo);
  774.         else
  775.         {
  776.             ODDisposePtr(sDialogInfo);
  777.             sDialogInfo = kODNULL;
  778.         }
  779.     }
  780.     
  781.     // Lastly, export the OD clipboard in case the user pastes into the dialog
  782.     ODPlatformTypeList* types = session->GetStorageSystem(ev)->CreatePlatformTypeList(ev, kODNULL);
  783.     types->AddLast(sEv, 'TEXT');
  784.     types->AddLast(sEv, 'PICT');
  785.     sSession->GetClipboard(sEv)->SetPlatformClipboard(sEv, types);
  786.     ODDeleteObject(types);
  787. }
  788.  
  789.  
  790. void ODDialogEnd()
  791. {
  792.     // Restore the Redo menu item deleted by DialogBegin
  793.     if ( sDialogInfo )
  794.     {
  795.         RestoreMenuItem(&sDialogInfo->redo);
  796.         ODDisposePtr(sDialogInfo);
  797.         sDialogInfo = kODNULL;        // Don't allow to be called again
  798.     }
  799. }
  800.  
  801.  
  802. void SaveAndDeleteMenuItem( MenuHandle menu, short item, MenuItemInfo *savedItem )
  803. {
  804.     savedItem->menu = menu;
  805.     savedItem->item = item;
  806.     GetMenuItemText(menu, item, savedItem->text);
  807.     GetItemCmd(menu, item, &savedItem->cmdChar);
  808.     GetItemIcon(menu, item, &savedItem->iconID);
  809.     GetItemMark(menu, item, &savedItem->markChar);
  810.     GetItemStyle(menu, item, &savedItem->textStyle);
  811.     DeleteMenuItem(menu, item);
  812.     InvalMenuBar();
  813. }
  814.  
  815.  
  816. void RestoreMenuItem( MenuItemInfo *savedItem )
  817. {
  818.     InsertMenuItem(savedItem->menu, savedItem->text, savedItem->item -1);
  819.         // Still set item text in case of non-meta meta-characters.
  820.     SetMenuItemText(savedItem->menu, savedItem->item, savedItem->text);
  821.     SetItemCmd(savedItem->menu, savedItem->item, savedItem->cmdChar);
  822.     SetItemIcon(savedItem->menu, savedItem->item, savedItem->iconID);
  823.     SetItemMark(savedItem->menu, savedItem->item, savedItem->markChar);
  824.     SetItemStyle(savedItem->menu, savedItem->item, savedItem->textStyle);
  825.     InvalMenuBar();
  826. }
  827.  
  828.  
  829. pascal void
  830. ODOutlineDefaultButtonDrawProc(DialogPtr theDialog, short theItem)
  831. {
  832.     // NOTE: this proc only works on buttons whose DITL ID is 1.  theItem
  833.     // is unused, and so it doesn't matter whether the user item to which
  834.     // this proc is assigned (via SetDialogItem) has any geographical
  835.     // relation to the button.
  836.     
  837.     ODUnused(theItem);
  838.     Rect         itemRect;
  839.     Handle        itemHandle;
  840.     short        itemKind;
  841.  
  842.     WindowPtr    buttonWindow;
  843.     WindowPtr    savePort;
  844.     PenState    savePen;
  845.     short        buttonOval;
  846.     Boolean        isColorPort;
  847.  
  848.     const short kColorPort = 0xC000;
  849.  
  850.     GetDialogItem(theDialog, kOKButton, &itemKind, &itemHandle, &itemRect);
  851.     ASSERT_CONTROL_ITEM(itemKind);
  852.  
  853.     GetPort(&savePort);
  854.     buttonWindow = (**(ControlHandle)itemHandle).contrlOwner;
  855.     SetPort(buttonWindow);
  856.     GetPenState(&savePen);
  857.     PenNormal();
  858.  
  859.     InsetRect(&itemRect, -4, -4);
  860.     FrameRoundRect(&itemRect, 16, 16);
  861.     buttonOval = ((itemRect.bottom - itemRect.top)/2)+2;
  862.  
  863.     isColorPort = ((((CGrafPtr)buttonWindow)->portVersion & kColorPort) == kColorPort);
  864.     
  865.     if ( (**(ControlHandle)itemHandle).contrlHilite == kControlInactive )
  866.     {
  867.         // Button is inactive, so outline with gray
  868.  
  869.         RGBColor    fgSaveColor;
  870.         RGBColor    fgNewColor;
  871.         RGBColor    bgColor;
  872.         Boolean        newGray = false;
  873.  
  874.         if ( isColorPort )
  875.         {
  876.             GetBackColor(&bgColor);
  877.             GetForeColor(&fgSaveColor);
  878.             fgNewColor = fgSaveColor;
  879.             
  880.             Rect globalRect = itemRect;
  881.             LocalToGlobal((Point *)&(globalRect.top));
  882.             LocalToGlobal((Point *)&(globalRect.bottom));
  883.             GDHandle targetDevice = GetMaxDevice(&globalRect);
  884.             
  885.             newGray = GetGray(targetDevice, &bgColor, &fgNewColor);
  886.         }
  887.  
  888.         if ( newGray )
  889.             RGBForeColor(&fgNewColor);
  890.         else
  891. #ifdef THINK_CPLUS
  892.             PenPat(ODQDGlobals.gray);
  893. #else
  894.             PenPat(&ODQDGlobals.gray);
  895. #endif
  896.  
  897.         PenSize(3, 3);
  898.         FrameRoundRect(&itemRect, buttonOval, buttonOval);
  899.         
  900.         if ( isColorPort )
  901.             RGBForeColor(&fgSaveColor);
  902.     }
  903.     else
  904.     {
  905.         // Button is active, so outline with black
  906. #ifdef THINK_CPLUS
  907.         PenPat(ODQDGlobals.black);
  908. #else
  909.         PenPat(&ODQDGlobals.black);
  910. #endif
  911.         PenSize(3, 3);
  912.         FrameRoundRect(&itemRect, buttonOval, buttonOval);
  913.     }
  914.  
  915.     SetPenState(&savePen);
  916.     SetPort(savePort);
  917. }
  918.  
  919.  
  920. UserItemUPP
  921. GetODOutlineDefaultButtonDrawProc( )
  922. {
  923.     if( !sOutlineDrawProc )
  924.         sOutlineDrawProc = NewUserItemProc(&ODOutlineDefaultButtonDrawProc);
  925.     return sOutlineDrawProc;
  926. }
  927.  
  928.  
  929. void
  930. ODUseDialogScriptData( DialogScriptData* dsd, DialogPtr dialog )
  931. {
  932.     sDlogScriptData = dsd;
  933.     dsd->SetDialog( dialog );
  934. }
  935.  
  936. pascal ODBoolean CheckKeyScriptChangeFilterProc( DialogPtr dialog,
  937.         EventRecord *event, short *itemHit)
  938. {
  939.     TEHandle teh = ((DialogPeek)dialog)->textH;
  940.     DialogScriptData* dsd = sDlogScriptData;
  941.     WASSERT( dsd );
  942.  
  943.     if ( dsd->Script() == ksmUninited )
  944.         dsd->SetScriptAndLockKeyboard();
  945.  
  946.     if ( event->what == keyDown )
  947.     {
  948.         if ( !dsd->ScriptChanged() )
  949.         {
  950.             ODScriptCode newScript = GetScriptManagerVariable(smKeyScript);
  951.             ODScriptCode fontScript = FontToScript((*teh)->txFont);
  952.             WASSERT( fontScript == dsd->Script() );
  953.             if ( fontScript != newScript )
  954.             {
  955.                 short newFont = GetScriptVariable( newScript, smScriptAppFond );
  956.                 (*teh)->txFont = newFont;
  957. //                TextFont(newFont);
  958.  
  959.                 dsd->SetScriptAndLockKeyboard( FontToScript(newFont) );
  960.             }
  961.         }
  962.     }
  963.  
  964.     // if this is the first time in this edit item, redraw in case
  965.     // we've switched fonts/scripts.
  966.     short currentItem = ((DialogPeek)dialog)->editField;
  967.     if ( dsd->ScriptChanged() && !dsd->ItemRedrawn(currentItem) )
  968.     {
  969.         dsd->SetRedrawn(currentItem);
  970.         short itemKind;
  971.         Handle ignoreH;
  972.         Rect ignoreR;
  973.         GetDialogItem( dialog, currentItem+1, &itemKind, &ignoreH, &ignoreR );
  974.         if ( itemKind == editText )
  975.         {
  976.             TECalText( teh );
  977.             Rect viewRect = (*teh)->viewRect;
  978.             TEUpdate( &viewRect, teh );
  979.         }
  980.     }
  981.  
  982.     // pass to the next filter proc.  This one just changes state, never
  983.     // consuming the event.
  984.     return kODFalse;
  985. }
  986.  
  987. void EnableOkButton(DialogPtr dlog, ODBoolean enable)
  988. {
  989.     Environment*    ev = somGetGlobalEnvironment();
  990.     short            itemType;
  991.     Handle            itemHandle;
  992.     Rect            itemRect;
  993.     ODBoolean        okEnabled;
  994.  
  995.     const short kButtonFrameInset = -4;
  996.  
  997.     GetDialogItem(dlog, kOKButton, &itemType, &itemHandle, &itemRect);    
  998.     ASSERT_CONTROL_ITEM(itemType);
  999.     okEnabled = (**(ControlHandle)itemHandle).contrlHilite == kControlActive;
  1000.  
  1001.     // there's nothing to do if the button is as it should be already
  1002.     if ( enable != okEnabled )
  1003.     {
  1004.         HiliteControl((ControlHandle)itemHandle, enable ? kControlActive : kControlInactive);
  1005.  
  1006.         // Invalidate the default button frame so it will be redrawn dim
  1007.         WindowPtr savePort;
  1008.         GetPort(&savePort);
  1009.         SetPort(dlog);
  1010.         InsetRect(&itemRect, kButtonFrameInset, kButtonFrameInset);
  1011.         InvalRect(&itemRect);
  1012.         SetPort(savePort);
  1013.     }
  1014.     ActivateControl(dlog, kOKButton, enable); // put state into the control ref
  1015. }
  1016.  
  1017. //    DrawGrayBox draws a gray box to be used as a separator.
  1018. //    On a ColorQD machine, a true-gray line is attempted.
  1019. //  On a B&W machine, a 50% pattern is used.
  1020.  
  1021. static pascal void DrawGrayBox(Rect *theBox)
  1022. {
  1023.     PenState    penState;
  1024.     GetPenState(&penState);
  1025.  
  1026.     PixPatHandle ppat = kODNULL;
  1027.     
  1028.     /* check if Color QuickDraw is available */    
  1029.     long response;
  1030.     if( Gestalt(gestaltQuickdrawFeatures, &response)==noErr
  1031.                 && BitTst(&response, 31-gestaltHasColor) ) {
  1032.         const RGBColor gray = {0x7FFF,0x7FFF,0x7FFF};
  1033.         ppat = NewPixPat();
  1034.         if( ppat )
  1035.             MakeRGBPat(ppat,&gray);
  1036.     }
  1037.  
  1038.     if( ppat )
  1039.         PenPixPat(ppat);
  1040.     else
  1041.         PenPat(&ODQDGlobals.gray);
  1042.         
  1043.     FrameRect(theBox);
  1044.     
  1045.     SetPenState(&penState);
  1046.  
  1047.     if( ppat )
  1048.         DisposePixPat(ppat);
  1049. }
  1050.  
  1051. pascal void DrawGrayBoxItem(DialogPtr theDialog, short theItem)
  1052. {
  1053.     Rect     boxRect;
  1054.     Handle    scratchHandle;
  1055.     short    scratchKind;
  1056.     
  1057.     GetDialogItem(theDialog, theItem, &scratchKind, &scratchHandle, &boxRect);
  1058.     DrawGrayBox(&boxRect);
  1059. }
  1060.  
  1061. pascal void DrawItemFrame(DialogPtr theDialog, short theItem)
  1062. {
  1063.     Rect     frameRect;
  1064.     Handle    scratchHandle;
  1065.     short    scratchKind;
  1066.     
  1067.     GetDialogItem(theDialog, theItem, &scratchKind, &scratchHandle, &frameRect);
  1068.     FrameRect(&frameRect);
  1069. }
  1070.  
  1071. //------------------------------------------------------------------------------
  1072. // SetDialogItemHandle
  1073. //------------------------------------------------------------------------------
  1074.  
  1075. void SetDialogItemHandle(DialogPtr theDialog, short itemNo, Handle itemHandle)
  1076. {
  1077.     short     itemType;
  1078.     Handle     dummy;
  1079.     Rect     scratchRect;
  1080.     
  1081.     GetDialogItem(theDialog, itemNo, &itemType, &dummy, &scratchRect);
  1082.     SetDialogItem(theDialog, itemNo, itemType, itemHandle, &scratchRect);
  1083. }
  1084.  
  1085. //------------------------------------------------------------------------------
  1086. // SetPopupControlValue
  1087. //------------------------------------------------------------------------------
  1088.  
  1089. void SetPopupControlValue(ControlHandle popupControlHandle, short itemValue)
  1090. {
  1091.     // The resource file must be in the chain in order for the popup to redraw.
  1092.     CUsingLibraryResources r;
  1093.     SetControlValue(popupControlHandle, itemValue);
  1094. }
  1095.  
  1096. ////////////////////////////////////////////////////////////////////////////////
  1097. // DrawITextInDlogBox
  1098. // Given a dialog, a rect and an ODIText*, truncate the text to fit in the
  1099. // rect and then draw it in the dialog.  Return result telling whether any
  1100. // change was made.
  1101. ////////////////////////////////////////////////////////////////////////////////
  1102.  
  1103. ODBoolean DrawITextInDlogBox( ODIText* itext, const Rect* textRect,
  1104.         DialogPtr dlog, ODBoolean tryToTruncate )
  1105. {
  1106.     WASSERT(dlog);
  1107.     WindowPtr savePort;
  1108.     GetPort(&savePort);
  1109.     SetPort(dlog);
  1110.  
  1111.     PenState savedPenState;
  1112.     GetPenState(&savedPenState);
  1113.     PenNormal();
  1114.  
  1115.     short saveFont = dlog->txFont;
  1116.     short savedTextMode = dlog->txMode;
  1117.     
  1118.     ODScriptCode scriptCode = GetITextScriptCode(itext);
  1119.     if ( scriptCode != FontToScript(saveFont) )
  1120.         TextFont(GetScriptVariable(scriptCode,smScriptAppFond));
  1121.     
  1122.     char buffer[256];
  1123.     ODSShort len = GetITextStringLength(itext);
  1124.     if ( len > 255 ) len = 255;
  1125.     ODBlockMove( GetITextPtr( itext ), buffer, len );
  1126.     short truncResult;
  1127.     if ( tryToTruncate )
  1128.         truncResult = TruncText( textRect->right - textRect->left - 1,
  1129.             buffer, &len, truncEnd);
  1130.     TETextBox( buffer, len,    textRect, teFlushDefault );
  1131.  
  1132.     TextFont(saveFont);
  1133.     TextMode(savedTextMode);
  1134.     SetPenState(&savedPenState);
  1135.     SetPort(savePort);
  1136.     return tryToTruncate? truncResult == 1 : kODFalse;    // 1 means truncation needed and successful
  1137. }
  1138.  
  1139. ////////////////////////////////////////////////////////////////////////////////
  1140. // FlashButtonItem
  1141. // Given a dialog and an item representing a button, flash that button,
  1142. // highlighting it for 8 ticks and then reverting.
  1143. ////////////////////////////////////////////////////////////////////////////////
  1144. void FlashButtonItem( DialogPtr dialog, short itemHit )
  1145. {
  1146.     Rect itemRect;
  1147.     short itemType;
  1148.     Handle itemHandle;
  1149.  
  1150.     GetDialogItem( dialog, itemHit, &itemType, &itemHandle, &itemRect);
  1151.     ASSERT_CONTROL_ITEM(itemType);
  1152.     HiliteControl((ControlHandle)itemHandle, kControlButtonPart);
  1153.     unsigned long ticks = TickCount() + 8;
  1154.     while ( TickCount() < ticks ) ;
  1155.     HiliteControl((ControlHandle)itemHandle, kControlActive);    // Turn off hilite
  1156. }
  1157.  
  1158. ////////////////////////////////////////////////////////////////////////////////
  1159. // ArrowKeyScrollList
  1160. // Given an "item" representing an up or down arrow or any of the other keys
  1161. // recognized by ODArrowKeyFilterProc above, a ListHandle indicating the list
  1162. // in which scrolling is taking place, pageSize giving the number of entries to
  1163. // be skipped by a "page down" command, and the zero-based index of the last
  1164. // entry in the list, do the right thing for the key selected.  So far this
  1165. // routine is used for lists embedded in dialogs, and it's up to the caller
  1166. // to determine which list is meant if there is more than one.
  1167. // NOTE that nothing happens currently if no list item is selected.  There needs
  1168. // to be a starting point for scrolling.
  1169. ////////////////////////////////////////////////////////////////////////////////
  1170.  
  1171. void ArrowKeyScrollList( ODSShort arrowItem, ListHandle listH,
  1172.         ODSShort pageSize, ODSShort lastEntry )
  1173. {
  1174.     ODSShort limitCell;
  1175.     ODSShort delta;
  1176.     switch( arrowItem )
  1177.     {
  1178.         case kODUpArrowItem:
  1179.             limitCell = 0;
  1180.             delta = -1;
  1181.             break;
  1182.  
  1183.         case kODDownArrowItem:
  1184.             limitCell = lastEntry;
  1185.             delta = 1;
  1186.             break;
  1187.  
  1188.         case kODPageUpArrowItem:
  1189.             limitCell = 0;
  1190.             delta = 0 - pageSize;
  1191.             break;
  1192.  
  1193.         case kODPageDownArrowItem:
  1194.             limitCell = lastEntry;
  1195.             delta = pageSize;
  1196.             break;
  1197.  
  1198.         case kODHomeArrowItem:
  1199.             limitCell = 0;
  1200.             delta = 0 - lastEntry;
  1201.             break;
  1202.  
  1203.         case kODEndArrowItem:
  1204.             limitCell = lastEntry;
  1205.             delta = lastEntry;
  1206.             break;
  1207.  
  1208.         default:
  1209.             WARN( "unknown arrow key/item" );
  1210.             return;
  1211.     }
  1212.  
  1213.     Cell selectedCell = {0,0};
  1214.     if ( !LGetSelect( true, &selectedCell, listH ) 
  1215.             || (selectedCell.v == limitCell) ) 
  1216.         return;
  1217.     LSetSelect( false, selectedCell, listH );
  1218.     selectedCell.v += delta;
  1219.     if ( selectedCell.v < 0 )
  1220.         selectedCell.v = 0;
  1221.     else if ( limitCell > 0 && selectedCell.v > limitCell )
  1222.         selectedCell.v = limitCell;
  1223.     LSetSelect( true, selectedCell, listH );
  1224.     LAutoScroll(listH);
  1225. }
  1226.  
  1227. //------------------------------------------------------------------------------
  1228. // ReplaceIntoString
  1229. //------------------------------------------------------------------------------
  1230. // Substitutes str0 for all occurances of "^0", and str1 for "^1", in the string
  1231. // retrieved from the 'STR ' resource identified by the first parameter.  Either
  1232. // str0 or str1 may be null.  Uses the current resource chain to find the 'STR '
  1233. // resource.
  1234.  
  1235. void ReplaceIntoString(ODSShort strResourceID,
  1236.                         ConstStr255Param str0,
  1237.                         ConstStr255Param str1,
  1238.                         Str255 destString)
  1239. {
  1240.     StringHandle msgHandle = GetString(strResourceID);
  1241.     if ( msgHandle )
  1242.     {
  1243.         DetachResource((Handle) msgHandle);
  1244.  
  1245.         ODHandle textHandle;
  1246.  
  1247.         HLock((Handle) msgHandle);
  1248.         ODHandle templateText = PStrToText(*msgHandle);
  1249.         HUnlock((Handle) msgHandle);
  1250.  
  1251.         if ( str0 )
  1252.         {
  1253.             textHandle = PStrToText(str0);
  1254.             if ( textHandle )
  1255.             {
  1256.                 ReplaceText((Handle) templateText, (Handle) textHandle, "\p^0");
  1257.                 ODDisposeHandle(textHandle);
  1258.             }
  1259.         }
  1260.         
  1261.         if ( str1 )
  1262.         {
  1263.             textHandle = PStrToText(str1);
  1264.             if ( textHandle )
  1265.             {
  1266.                 ReplaceText((Handle) templateText, (Handle) textHandle, "\p^1");
  1267.                 ODDisposeHandle(textHandle);
  1268.             }
  1269.         }
  1270.  
  1271.         TextToPStr(templateText, destString);
  1272.  
  1273.         ODDisposeHandle(templateText);
  1274.         DisposeHandle((Handle) msgHandle);
  1275.     }
  1276.     else
  1277.         if( ResError() != memFullErr )
  1278.         {
  1279.             WARN("ReplaceIntoString didn't find STR %hd",strResourceID);
  1280.             destString[0] = 0;
  1281.         }
  1282. }
  1283.  
  1284.  
  1285. //------------------------------------------------------------------------------
  1286. // LookupString
  1287. //
  1288. // Searches a MacApp-style 'errs' table for a value, then looks up the
  1289. // associated string from the associated 'STR#' resource.
  1290. //------------------------------------------------------------------------------
  1291. ODBoolean LookupString(ODError value,
  1292.                        short resourceID,
  1293.                        Str255 str)
  1294. {
  1295.     struct ErrRecord
  1296.     {
  1297.         ODError lowErr, highErr;
  1298.         ODULong index;
  1299.     };
  1300.  
  1301.     typedef ErrRecord* ErrRecordPointer;
  1302.     typedef ErrRecordPointer* ErrRecordHandle;
  1303.  
  1304.     CUsingLibraryResources r;
  1305.  
  1306.     str[0] = 0;
  1307.     ErrRecordHandle table = (ErrRecordHandle)GetResource('errs', resourceID);
  1308.     
  1309.     if (table)
  1310.     {
  1311.         short lenTab;
  1312.         short strID = 0;
  1313.         
  1314.         ErrRecordPointer pEntry = *table;    // careful, pointing into unlocked resource...
  1315.  
  1316.         lenTab = (short)(GetHandleSize((Handle)table) / sizeof(ErrRecord));
  1317.         for (short i = 1; i <= lenTab; ++i, ++pEntry)
  1318.         {
  1319.             if (pEntry->lowErr == 0)
  1320.                 strID = (short)(pEntry->index);
  1321.             else if ((pEntry->lowErr <= value) && (value <= pEntry->highErr))
  1322.             {
  1323.                 if (pEntry->index > 0)
  1324.                 {
  1325.                     GetIndString(str, strID, (short)(pEntry->index));
  1326.                 }
  1327.                 return kODTrue;
  1328.             }
  1329.         }
  1330.     }
  1331.     return kODFalse;
  1332. } // SearchErrTable 
  1333.  
  1334.  
  1335.  
  1336. //--------------------------------------------------------------------
  1337. // GetODITextInd
  1338. // Gets string # (index) from the 'STR#' resource given by resID 
  1339. // into an IText* whose script and language codes are those of 
  1340. // the current system script.
  1341. //--------------------------------------------------------------------
  1342.  
  1343. ODIText* GetODITextInd(short resID, short index)
  1344. {
  1345.     Str255 pStr = "\p";
  1346.     GetIndString(pStr, resID, index);
  1347.     ODScriptCode script = FontToScript( GetSysFont() );
  1348.     return CreateITextPString(script,
  1349.                             GetScriptVariable(script, smScriptLang), 
  1350.                             pStr);
  1351. }
  1352.  
  1353.  
  1354. //--------------------------------------------------------------------
  1355. // GetODIText
  1356. // Turns an 'STR ' resource of the given resID into an ODIText* whose
  1357. // language and script codes are those of the current system script.
  1358. //--------------------------------------------------------------------
  1359.  
  1360. ODIText* GetODIText(short resID)
  1361. {
  1362.     Handle textHandle;
  1363.     ODIText* iText = kODNULL;
  1364.     
  1365.     textHandle = (Handle)GetString(resID);
  1366.     
  1367.     if ( textHandle != kODNULL )
  1368.     {
  1369.         // CreateIText copies the values passed into it, so we don't
  1370.         // have to worry about the resource handle moving outside of
  1371.         // the scope of this function.
  1372.  
  1373.         ODScriptCode script = GetScriptManagerVariable(smSysScript);
  1374.         ODLangCode lang = GetScriptVariable(script, smScriptLang);
  1375.         HLock(textHandle);
  1376.         iText = CreateIText( script, lang, (StringPtr)*textHandle );
  1377.             
  1378.         ReleaseResource(textHandle);
  1379.     }
  1380.     
  1381.     return iText;
  1382. }
  1383.  
  1384. //------------------------------------------------------------------------------
  1385. // SetDialogTextStyle
  1386. //------------------------------------------------------------------------------
  1387.  
  1388. void SetDialogTextStyle(DialogPtr dlg, short finfResourceID,
  1389.         ODScriptCode script)
  1390. {
  1391. #if PRAGMA_ALIGN_SUPPORTED
  1392. #pragma options align=mac68k
  1393. #endif
  1394.  
  1395.     typedef struct {
  1396.         short count;
  1397.         short fontNumber;
  1398.         short fontStyl;
  1399.         short fontSize;
  1400.     } FontSpec;
  1401.  
  1402. #if PRAGMA_ALIGN_SUPPORTED
  1403. #pragma options align=reset
  1404. #endif
  1405.  
  1406.     typedef FontSpec** FontSpecHandle;
  1407.     FontInfo    finfo;
  1408.     
  1409.     FontSpecHandle finfHandle = (FontSpecHandle) GetResource('finf', finfResourceID);
  1410.  
  1411.     if ( finfHandle )
  1412.     {
  1413.         SetPort(dlg);
  1414.         
  1415.         short font;
  1416.         if ( script != smCurrentScript )
  1417.             font = GetScriptVariable( script, smScriptAppFond );    // <eeh> smScriptSysFond better?
  1418.         else
  1419.             font = (**finfHandle).fontNumber;
  1420.         
  1421.         TextFont(font);
  1422.         TextFace((**finfHandle).fontStyl);
  1423.         TextSize((**finfHandle).fontSize);
  1424.         TEHandle te = ((DialogPeek)dlg)->textH;
  1425.         (**te).txFont = font;
  1426.         (**te).txSize = (**finfHandle).fontSize;
  1427.         (**te).txFace = (**finfHandle).fontStyl;
  1428.         GetFontInfo(&finfo);
  1429.         (**te).lineHeight = finfo.leading + finfo.ascent + finfo.descent;
  1430.         (**te).fontAscent = finfo.ascent;
  1431.         TECalText(te);
  1432.         ReleaseResource((Handle) finfHandle);
  1433.     } else
  1434.         if( ResError() != memFullErr )
  1435.             WARN("SetDialogTextStyle didn't find 'finf' %hd",finfResourceID);
  1436. }
  1437.  
  1438. //-------------------------------------------------------------------------------------
  1439. // SetPopupItemScript
  1440. //-------------------------------------------------------------------------------------
  1441. // "scriptID" should be a true script code, not an implicit script code
  1442. //
  1443. // This routine assumes the popup is drawn using the font of the current port.
  1444. //
  1445. // Setting the script of a popup menu item has two bad consequences:
  1446. // The title and item appear in bold face, and the width of the
  1447. // menu is increased.  This is true even if the script specified
  1448. // is the same as the default script!  So only specify a script if its different.
  1449.  
  1450. void SetPopupItemScript(MenuHandle menu, short itemNum, short scriptID)
  1451. {
  1452.     const ODSShort kUseSpecificScript = 0x1c;
  1453.  
  1454.     ODSLong    savedSMFontForceFlag = GetScriptManagerVariable(smFontForce);
  1455.     SetScriptManagerVariable(smFontForce, false);
  1456.  
  1457.     // Since the popup is drawn using the window font, compare the argument
  1458.     // script to the script of the current graphics port.
  1459.     GrafPtr curPort;
  1460.     GetPort(&curPort);
  1461.  
  1462.     if ( scriptID == smSystemScript )
  1463.         scriptID = (short) GetScriptManagerVariable(smSysScript);
  1464.  
  1465.     if ( scriptID != FontToScript(curPort->txFont) )
  1466.     {
  1467.         SetItemCmd(menu, itemNum, kUseSpecificScript);
  1468.         SetItemIcon(menu, itemNum, scriptID);
  1469.     }
  1470.     
  1471.     SetScriptManagerVariable(smFontForce, savedSMFontForceFlag);
  1472. }
  1473.  
  1474.  
  1475. //-------------------------------------------------------------------------------------
  1476. // Implementation of DialogScriptData class
  1477. //-------------------------------------------------------------------------------------
  1478.  
  1479. DialogScriptData::DialogScriptData()
  1480. {
  1481.     fItemRedrawn = 0L;
  1482.     fMustUnlock = kODFalse;
  1483.     fScript = ksmUninited;
  1484. }
  1485.  
  1486. DialogScriptData::~DialogScriptData()
  1487. {
  1488.     if ( fMustUnlock )
  1489.         this->ReleaseLockout();
  1490. }
  1491.  
  1492. void DialogScriptData::SetScriptAndLockKeyboard()
  1493. {
  1494. //    this->SetScriptAndLockKeyboard( FontToScript( GetAppFont() ) );
  1495.     WASSERT( FontToScript( GetSysFont()) == FontToScript( GetAppFont() ));
  1496.     this->SetScriptAndLockKeyboard( FontToScript( GetSysFont() ) );
  1497. }
  1498.  
  1499. // There are two cases we need to be aware of here when the script passed
  1500. // in comes from an existing IText* and isn't Roman.  First, it's possible
  1501. // that the keyscript is not yet set to that script (that it's still Roman).
  1502. // Second, the dialog may not be in a state to properly display that text.
  1503.  
  1504. void DialogScriptData::SetScriptAndLockKeyboard( ODScriptCode script )
  1505. {
  1506.     if ( script != smRoman )    // lock all changes out: switch to Roman will
  1507.     {                            // result in non-Roman text being garbage
  1508.         if ( GetScriptManagerVariable(smKeyScript) != script )
  1509.             KeyScript( script );    // script may not yet have been set
  1510.  
  1511.         WASSERT(fDialog);
  1512.         TEHandle teh = ((DialogPeek)fDialog)->textH;
  1513.         if ( FontToScript( (*teh)->txFont ) != script )
  1514.         {
  1515.             (*teh)->txFont = GetScriptVariable( script, smScriptSysFond );            
  1516.         }
  1517.  
  1518. //        KeyScript( smKeyDisableKybdSwitch );    // <eeh> 1/6
  1519.         fMustUnlock = kODTrue;
  1520.     }
  1521.     fScript = script;
  1522. }
  1523.  
  1524. void DialogScriptData::ReleaseLockout()
  1525. {
  1526.     if ( fMustUnlock != kODFalse )
  1527.     {
  1528. //        KeyScript( smKeyEnableKybds );    // <eeh> 1/6
  1529.         fMustUnlock = kODFalse;
  1530.     }
  1531. }
  1532.  
  1533. ODBoolean DialogScriptData::ItemRedrawn( short item )
  1534. {
  1535.     WASSERT( item < kMaxNumItems );
  1536.     return (fItemRedrawn & 1L<<(item-1)) != 0;
  1537. }
  1538.  
  1539. void DialogScriptData::SetRedrawn( short item )
  1540. {
  1541.     WASSERT( item < kMaxNumItems );
  1542.     fItemRedrawn |= 1L<<(item-1);
  1543. }
  1544.